/**************************************************************************//**
 * @file     SpiRead.c
 * @brief    SPI functions for Spiloader
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/
#include "W55FA93_reg.h"
#include "wblib.h"


#define	SPICMD_DUMMY				0x00
#define	SPICMD_READ_DATA			0x03

#define CACHE_BIT31	BIT31

int spiActive(int port)
{
	outp32(REG_SPI0_CNTRL, inp32(REG_SPI0_CNTRL)|0x01);
	while(inp32(REG_SPI0_CNTRL) & 0x01);

	return 0;
}

int spiTxLen(int port, int count, int bitLen)//ok
{
	UINT32 reg;

	reg = inp32(REG_SPI0_CNTRL);

	if ((count < 0) || (count > 3))
		return 1;

	if ((bitLen <= 0) || (bitLen > 32))
		return 1;

	if (bitLen == 32)
		reg = reg & 0xffffff07;
	else
		reg = (reg & 0xffffff07) | (bitLen << 3);
		
	reg = (reg & 0xfffffcff) | (count << 8);

	outp32(REG_SPI0_CNTRL, reg);

	return 0;
}

int usiCheckBusy()
{
	// check status
	outp32(REG_SPI0_SSR, inp32(REG_SPI0_SSR) | 1);	// CS0

	// status command
	outp32(REG_SPI0_TX0, 0x05);
	spiTxLen(0, 0, 8);
	spiActive(0);

	// get status
	while(1)
	{
		outp32(REG_SPI0_TX0, 0xff);
		spiTxLen(0, 0, 8);
		spiActive(0);
		if (((inp32(REG_SPI0_RX0) & 0xff) & 0x01) != 0x01)
			break;
	}


	outp32(REG_SPI0_SSR, inp32(REG_SPI0_SSR) & 0xfe);	// CS0


	return 0;
}


void EDMAMasterRead(UINT32 u32DestAddr, UINT32 u32Length)
{
	UINT32 u32SFRCSR,u32Value,u32SPIBitLen, eTransferWidth  =0;
	UINT8* pu8SrcAddr;	    
	
	// Set Byte Endian
	outp32(REG_SPI0_CNTRL, inp32(REG_SPI0_CNTRL) | 1<<20);
		
	u32SPIBitLen=0;	
		
    outp32(REG_SPI0_CNTRL, (inp32(REG_SPI0_CNTRL) & ~Tx_BIT_LEN) | u32SPIBitLen<<3);    
	
	pu8SrcAddr = (UINT8 *)SPI0_BA;
	u32SFRCSR = REG_PDMA_CSR1;
	
	outp32(REG_PDMA_SAR1, REG_SPI0_RX0);	   							// EDMA Source
	outp32(REG_PDMA_DAR1,(u32DestAddr| 0x80000000));				// EDMA Destination
	outp32(REG_PDMA_BCR1, u32Length);							// EDMA Byte Count  
	u32Value = 0x00000005;									// Src:Fix, Dest:Inc, IP2Mem, EDMA enable
	//u32Value = u32Value | (eTransferWidth<<19);				// Change APB_TWS 	  
	
	outp32(u32SFRCSR,u32Value);								// EDMA Transer width 	
	
    outp32(u32SFRCSR,inp32(u32SFRCSR) | TRIG_EN);		    // Enable EDMA Trig_En
	
	outp32(REG_SPI0_EDMA,0x03);							// Enable SPI EDMA Read & Start		
    outp32(REG_SPI0_CNTRL, inp32(REG_SPI0_CNTRL) |1);	    // master start	
    
    while(inp32(u32SFRCSR) & TRIG_EN);
    
}

int SPIReadFast(BOOL bEDMAread, UINT32 addr, UINT32 len, UINT32 *buf)
{
	int volatile i, j;
	UINT32 u32Tmp,u32Count;
	//sysprintf("Load file length 0x%x, execute address 0x%x\n", len, (UINT32)buf);

	outp32(REG_SPI0_CNTRL, inp32(REG_SPI0_CNTRL) & ~(1<<20));		// disabe BYTE endian
	
	outp32(REG_SPI0_SSR, inp32(REG_SPI0_SSR) | 0x01);	// CS0

	buf = (UINT32 *) ((UINT32)buf | (UINT32)CACHE_BIT31);

	// read command
	outp32(REG_SPI0_TX0, 0x0B);
	spiTxLen(0, 0, 8);
	spiActive(0);

	// address
	outp32(REG_SPI0_TX0, addr);
	spiTxLen(0, 0, 24);
	spiActive(0);

	// dummy byte
	outp32(REG_SPI0_TX0, 0xff);
	spiTxLen(0, 0, 8);
	spiActive(0);
	if(bEDMAread)
	{
	  	EDMAMasterRead((UINT32)buf, len);
	}
	else
	{
#if 	0
		u32Count = len/4;
		if(len % 4)
			u32Count++;
			
		// data
		for (i=0; i<u32Count; i++)
		{
			outp32(REG_SPI0_TX0, 0xffffffff);
			spiTxLen(0, 0, 32);
			spiActive(0);
			u32Tmp = inp32(REG_SPI0_RX0);
			*buf++ = ((u32Tmp & 0xFF) << 24) | ((u32Tmp & 0xFF00) << 8) | ((u32Tmp & 0xFF0000) >> 8)| ((u32Tmp & 0xFF000000) >> 24);
		}
#else
	u32Count = len/16;
	if(len % 16)
		u32Count++;

	outpw(REG_SPI0_CNTRL, inpw(REG_SPI0_CNTRL) |BYTE_ENDIN);
	spiTxLen(0, 3, 32);

	// data	 
	for (i=0; i<u32Count; i++)
	{
		//spiTxLen(0, 3, 32);
		outpw(REG_SPI0_TX0, 0xffffffff);	
		outpw(REG_SPI0_TX1, 0xffffffff);	
		outpw(REG_SPI0_TX2, 0xffffffff);	
		outpw(REG_SPI0_TX3, 0xffffffff);	
		spiActive(0);
		for(j=0; j<4; j++)
		{
			*buf++ = inp32(REG_SPI0_RX0 + j*4);			
		}
	}	

	outpw(REG_SPI0_CNTRL, inpw(REG_SPI0_CNTRL) & ~BYTE_ENDIN);
	spiTxLen(0, 0, 32);
	
#endif
	}
	outp32(REG_SPI0_SSR, inp32(REG_SPI0_SSR) & 0xfe);	// CS0
	

	return 0;
}

VOID SPI_OpenSPI(VOID)
{
	outp32(REG_APBCLK, inp32(REG_APBCLK) | SPIMS0_CKE);
	outp32(REG_GPDFUN, inp32(REG_GPDFUN) | (MF_GPD15|MF_GPD14|MF_GPD13|MF_GPD12));
	outp32(REG_SPI0_DIVIDER, 0x00);
}

VOID SPI_CloseSPI(VOID)
{
	outp32(REG_APBCLK, inp32(REG_APBCLK) & ~SPIMS0_CKE);
	/* Disable Pin function */  	
	outp32(REG_GPDFUN, inp32(REG_GPDFUN) & ~(MF_GPD15|MF_GPD14|MF_GPD13|MF_GPD12));	
}






























